﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using X3DXNA.X3DSchema;
using System.IO;
using System.Xml;
using System.Xaml;
using Microsoft.Xna.Framework;
using X3DXNA.basicModels;
using X3DXNA.interfaces;

namespace X3DXNA.utils
{
    public static class utility
    {
        public static X3D openX3D(String file)
        {
            TextReader textReader = File.OpenText(file);
            string content = textReader.ReadToEnd();
            int startIndex = content.IndexOf("<X3D");
            startIndex += 4;
            int endIndex = content.IndexOf(">", startIndex);
            content = content.Remove(startIndex, endIndex - startIndex);

            content = content.Replace("<X3D>", "<X3D xmlns='clr-namespace:X3DXNA.X3DSchema;assembly=X3DXNA'>");
            textReader.Close();
            

            byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(content);
            MemoryStream stream = new MemoryStream(byteArray);

            //NameTable nt = new NameTable();
            //XmlNamespaceManager nm = new XmlNamespaceManager(nt);
            //nm.AddNamespace("X3D", "X3DXNA.X3DSchema");
            //XmlParserContext pc = new XmlParserContext(null, nm, null, XmlSpace.Preserve);

            XmlTextReader xmlTextReader = new XmlTextReader(stream);
            xmlTextReader.DtdProcessing = DtdProcessing.Ignore;
            //xmlTextReader.Namespaces = false;
            
            //XamlXmlReaderSettings a = new XamlXmlReaderSettings();
            //a.LocalAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            //a.LocalAssembly.CreateInstance("X3DXNA.X3DSchema");
            XamlXmlReader xamlXmlReader = new XamlXmlReader(xmlTextReader);

            return (X3D)XamlServices.Load(xamlXmlReader);
        }

        /// <summary>
        /// Restituisce un Vector3 da un ingresso String. Premessa, la String in ingresso deve essere composta da gruppi di 
        /// float separati da uno spazio. Es: String input = "0.3 0.5 1.2";
        /// </summary>
        /// <param name="input">La String in ingresso da convertire. ATTENZIONE, controllare che sia != NULL</param>
        /// <returns>Il Vector3 convertito.</returns>
        public static Vector3 stringToVector3(String input)
        {
            if (input == null)
                throw new Exception("Il valore passato in argomento è null");
            input = input.Replace('.', ',');
            var splitted = input.Split(' ');
            return new Vector3(float.Parse(splitted[0]), float.Parse(splitted[1]), float.Parse(splitted[2]));
        }

        /// <summary>
        /// Restituisce un Vector4 da un ingresso String. Premessa, la String in ingresso deve essere composta da gruppi di 
        /// float separati da uno spazio. Es: String input = "0.3 0.5 1.2 1.2";
        /// </summary>
        /// <param name="input">La String in ingresso da convertire. ATTENZIONE, controllare che sia != NULL</param>
        /// <returns>Il Vector4 convertito.</returns>
        public static Vector4 stringToVector4(String input)
        {
            input = input.Replace('.', ',');
            var splitted = input.Split(' ');
            return new Vector4(float.Parse(splitted[0]), float.Parse(splitted[1]), float.Parse(splitted[2]), float.Parse(splitted[3]));
        }

        /// <summary>
        /// Restituisce un valore float da un ingresso String.
        /// </summary>
        /// <param name="input">La String da convertire.</param>
        /// <returns>Il float convertito.</returns>
        public static float stringToFloat(String input)
        {
            if (input != null)
            {
                input = input.Replace('.', ',');
                return float.Parse(input);
            }
            else return 0.0f;
        }

        /// <summary>
        /// Restituisce un valore bool da un ingresso String.
        /// </summary>
        /// <param name="input">La String da convertire.</param>
        /// <returns>Il bool convertito.</returns>
        public static bool stringToBool(String input)
        {
            if (input.Equals("true"))
                return true;
            else if (input.Equals("false"))
                return false;
            else 
                throw new Exception("Il valore passato in argomento è null");
        }

        public static Vector4 stringToVector4Rotation(String input)
        {
            if (input != null)
            {
                return stringToVector4(input);
            }
            else return new Vector4(0, 0, 1, 0);
        }
        public static Vector3 stringToVector3Scalation(String input)
        {
            if (input != null)
            {
                return stringToVector3(input);
            }
            else
                return Vector3.One;
        }
        public static Vector3 stringToVector3Translation(String input)
        {
            if (input != null)
            {
                return stringToVector3(input);
            }
            else
                return Vector3.Zero;
        }
        public static Vector3 stringToVector3Color(String input)
        {
            if (input != null)
            {
                return stringToVector3(input);
            }
            else
                return Vector3.Zero;
        }
        public static Quaternion vector4ToQuaternionRotation(Vector4 input)
        {
            return Quaternion.CreateFromAxisAngle(new Vector3(input.X, input.Y, input.Z), input.W);
        }

        /// <summary>
        /// Funzione che data una lista di Usable, ritorna l'oggetto che ha come proprietà DEF la stringa specificata
        /// come parametro.
        /// </summary>
        /// <param name="list">La lista di Usable da controllare.</param>
        /// <param name="DEF">La stringa del DEF da cercare.</param>
        /// <returns>Ritorna l'usable cercato. NULL se non viene trovato nessun elemento.</returns>
        public static IUsable findUsable(List<IUsable> list, String DEF)
        {
            foreach (IUsable u in list)
            {
                if (u.DEF.Equals(DEF))
                    return u;
            }
            return null;
        }

        public static Int16[] stringToIndices(String indices)
        {
            if (indices != null)
            {
                String[] a = indices.Split(' ');
                List<Int16> temp = new List<Int16>();
                foreach (String partial in a)
                {
                    if (!partial.Equals("") && !partial.Equals(" ") && !partial.Equals("-1"))
                    {
                        temp.Add(Int16.Parse(partial));
                    }
                }
                return temp.ToArray();
            }

            else
                return null;
        }

        public static Int16[] stringToIndicesIndexedFaceSet(String indices)
        {
            if (indices != null)
            {
                List<Int16> listOfInt16 = new List<Int16>();
                String[] a = indices.Split(new String[]{"-1"}, StringSplitOptions.RemoveEmptyEntries);

                foreach (String b in a)
                {
                    String[] temp1 = b.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
                    listOfInt16.Add(Int16.Parse(temp1[0]));
                    listOfInt16.Add(Int16.Parse(temp1[1]));
                    listOfInt16.Add(Int16.Parse(temp1[2]));
                    listOfInt16.Add(Int16.Parse(temp1[0]));
                    listOfInt16.Add(Int16.Parse(temp1[2]));
                    listOfInt16.Add(Int16.Parse(temp1[3]));
                }

                return listOfInt16.ToArray();
            }

            else
                return null;
        }

        public static Vector3[] stringToVertices(String indices)
        {
            if (indices != null)
            {
                indices = indices.Replace('.', ',');
                String[] a = indices.Split(' ');
                List<float> temp = new List<float>();
                foreach (String partial in a)
                {
                    if (!partial.Equals("") && !partial.Equals(" "))
                    {
                        temp.Add(float.Parse(partial));
                    }
                }

                List<Vector3> vertices = new List<Vector3>();

                for (int i = 0; i < temp.Count; i += 3)
                {
                    vertices.Add(new Vector3(temp[i], temp[i + 1], temp[i + 2]));
                }

                return vertices.ToArray();
            }
            else
                return null;
        }

        public static float[] stringToFloatArray(String value)
        {
            value = value.Replace(",", " ");
            value = value.Replace('.', ',');
            String[] a = value.Split(' ');
            List<float> temp = new List<float>();
            foreach (String partial in a)
            {
                if (!partial.Equals(""))
                    temp.Add(float.Parse(partial));
            }

            return temp.ToArray();
        }

        public static Color[] stringToColorArray(String value)
        {
            float[] temp = stringToFloatArray(value);
            List<Color> tempColor = new List<Color>();
            for (int i = 0; i < temp.Length; i += 3)
            {
                tempColor.Add(new Color(temp[i], temp[i + 1], temp[i + 2]));
            }

            return tempColor.ToArray();
        }

        public static Vector3[] stringToVector3Array(String value)
        {
            float[] temp = stringToFloatArray(value);
            List<Vector3> tempVector3 = new List<Vector3>();
            for (int i = 0; i < temp.Length; i += 3)
            {
                tempVector3.Add(new Vector3(temp[i], temp[i + 1], temp[i + 2]));
            }

            return tempVector3.ToArray();
        }

        public static Vector4[] stringToVector4Array(String value)
        {
            float[] temp = stringToFloatArray(value);
            List<Vector4> tempVector4 = new List<Vector4>();
            for (int i = 0; i < temp.Length; i += 4)
            {
                tempVector4.Add(new Vector4(temp[i], temp[i + 1], temp[i + 2], temp[i+3]));
            }

            return tempVector4.ToArray();
        }

        public static Quaternion[] stringToQuaternionArray(String value)
        {
            float[] temp = stringToFloatArray(value);
            List<Quaternion> tempQuaternion = new List<Quaternion>();
            for (int i = 0; i < temp.Length; i += 4)
            {
                tempQuaternion.Add(Quaternion.CreateFromAxisAngle(new Vector3(temp[i], temp[i + 1], temp[i + 2]), temp[i + 3]));
            }

            return tempQuaternion.ToArray();
        }
    }
}
